/*!
 * \file md_api.cpp
 * \project AI_CTP
 * 
 * \brief CTP行情API实现 - 基于wt_ctp成功实现
 */

#include "md_api.hpp"
#include <iostream>
#include <ctime>
#include <sstream>
#include <iomanip>
#include <chrono>
#include <algorithm>

namespace ctp_api {

// KlineBuilder实现
void KlineBuilder::add_tick(const TickInfo& tick) {
    std::lock_guard<std::mutex> lock(mutex_);
    
    // 为每个周期更新K线
    for (int period : {1, 3, 12, 30}) {
        update_bar(tick.instrument_id, period, tick);
    }
}

std::vector<BarInfo> KlineBuilder::get_bars(const std::string& instrument_id, int period) const {
    std::lock_guard<std::mutex> lock(mutex_);
    
    std::vector<BarInfo> result;
    auto it = bars_.find(instrument_id);
    if (it != bars_.end()) {
        auto period_it = it->second.find(period);
        if (period_it != it->second.end()) {
            result.push_back(period_it->second);
        }
    }
    return result;
}

uint64_t KlineBuilder::get_bar_time(const std::string& time_str, int period) {
    // 简单的时间转换实现
    struct tm tm_time = {};
    sscanf(time_str.c_str(), "%d:%d:%d", &tm_time.tm_hour, &tm_time.tm_min, &tm_time.tm_sec);
    
    int minute = tm_time.tm_hour * 60 + tm_time.tm_min;
    int bar_minute = (minute / period) * period;
    
    return static_cast<uint64_t>(bar_minute);
}

void KlineBuilder::update_bar(const std::string& instrument_id, int period, const TickInfo& tick) {
    uint64_t bar_time = get_bar_time(tick.update_time, period);
    
    auto& bar = bars_[instrument_id][period];
    
    if (bar.bar_time != bar_time) {
        // 新的K线
        bar.instrument_id = instrument_id;
        bar.bar_time = bar_time;
        bar.period = period;
        bar.open = tick.last_price;
        bar.high = tick.last_price;
        bar.low = tick.last_price;
        bar.close = tick.last_price;
        bar.volume = tick.volume;
        bar.turnover = tick.turnover;
        bar.open_interest = tick.open_interest;
        bar.time_str = tick.update_time;
    } else {
        // 更新现有K线
        bar.high = std::max(bar.high, tick.last_price);
        bar.low = std::min(bar.low, tick.last_price);
        bar.close = tick.last_price;
        bar.volume = tick.volume;
        bar.turnover = tick.turnover;
        bar.open_interest = tick.open_interest;
    }
}

// MdApi实现
MdApi::MdApi() 
    : md_api_(nullptr),
      state_(MdState::DISCONNECTED),
      request_id_(0),
      kline_builder_(std::make_unique<KlineBuilder>()),
      kline_enabled_(false),
      enable_kline_output_(false),
      initialized_(false) {
}

MdApi::~MdApi() {
    stop();
}

bool MdApi::init(const std::string& broker_id, const std::string& user_id, 
                 const std::string& password, const std::string& front_addr) {
    std::lock_guard<std::mutex> lock(mutex_);
    
    if (initialized_) {
        return false;
    }
    
    broker_id_ = broker_id;
    user_id_ = user_id;
    password_ = password;
    front_addr_ = front_addr;
    
    // 根据官方建议，使用空字符串让CTP API自动处理流文件路径
    // 这是解决"can not open CFlow file"错误的标准方法
    flow_path_ = "";
    
    // 创建CTP API实例 - 使用空路径避免CFlow文件错误
    md_api_ = CThostFtdcMdApi::CreateFtdcMdApi(flow_path_.c_str());
    if (!md_api_) {
        std::cerr << "Failed to create CTP MD API" << std::endl;
        return false;
    }
    
    // 注册回调
    md_api_->RegisterSpi(this);
    
    initialized_ = true;
    return true;
}

void MdApi::start() {
    std::lock_guard<std::mutex> lock(mutex_);
    
    if (!initialized_ || !md_api_) {
        return;
    }
    
    // 注册前置地址
    char* front_addr = const_cast<char*>(front_addr_.c_str());
    md_api_->RegisterFront(front_addr);
    
    // 初始化API
    md_api_->Init();
    
    state_ = MdState::CONNECTING;
}

void MdApi::stop() {
    std::lock_guard<std::mutex> lock(mutex_);
    
    if (md_api_) {
        md_api_->Release();
        md_api_ = nullptr;
    }
    
    state_ = MdState::DISCONNECTED;
    initialized_ = false;
}

bool MdApi::is_connected() const {
    return state_ == MdState::READY;
}

bool MdApi::subscribe(const std::vector<std::string>& instruments) {
    if (!md_api_ || state_ != MdState::READY) {
        return false;
    }
    
    // 转换为CTP需要的格式
    std::vector<char*> instrument_ptrs;
    for (const auto& inst : instruments) {
        instrument_ptrs.push_back(const_cast<char*>(inst.c_str()));
    }
    
    int result = md_api_->SubscribeMarketData(instrument_ptrs.data(), instrument_ptrs.size());
    return result == 0;
}

bool MdApi::unsubscribe(const std::vector<std::string>& instruments) {
    if (!md_api_ || state_ != MdState::READY) {
        return false;
    }
    
    // 转换为CTP需要的格式
    std::vector<char*> instrument_ptrs;
    for (const auto& inst : instruments) {
        instrument_ptrs.push_back(const_cast<char*>(inst.c_str()));
    }
    
    int result = md_api_->UnSubscribeMarketData(instrument_ptrs.data(), instrument_ptrs.size());
    return result == 0;
}

void MdApi::enable_kline(const std::vector<int>& periods) {
    std::lock_guard<std::mutex> lock(mutex_);
    kline_enabled_ = true;
    kline_periods_ = periods;
    enable_kline_output_ = true;
}

void MdApi::disable_kline() {
    std::lock_guard<std::mutex> lock(mutex_);
    kline_enabled_ = false;
    enable_kline_output_ = false;
}

void MdApi::set_callback(std::shared_ptr<IMdCallback> callback) {
    std::lock_guard<std::mutex> lock(mutex_);
    callback_ = callback;
}

std::vector<BarInfo> MdApi::get_klines(const std::string& instrument_id, int period_minutes, int count) {
    if (kline_builder_) {
        return kline_builder_->get_bars(instrument_id, period_minutes);
    }
    return {};
}

// CTP回调函数实现
void MdApi::OnFrontConnected() {
    std::cout << "Connected to CTP front server" << std::endl;
    state_ = MdState::CONNECTED;
    
    if (callback_) {
        callback_->on_connected();
    }
    
    // 发送登录请求
    CThostFtdcReqUserLoginField req = {};
    safe_copy_string(req.BrokerID, broker_id_, sizeof(req.BrokerID));
    safe_copy_string(req.UserID, user_id_, sizeof(req.UserID));
    safe_copy_string(req.Password, password_, sizeof(req.Password));
    
    state_ = MdState::LOGGING_IN;
    int result = md_api_->ReqUserLogin(&req, get_next_request_id());
    
    if (result != 0) {
        std::cerr << "Login request failed: " << result << std::endl;
    }
}

void MdApi::OnFrontDisconnected(int nReason) {
    std::cout << "Disconnected from CTP front server, reason: " << nReason << std::endl;
    state_ = MdState::DISCONNECTED;
    
    if (callback_) {
        callback_->on_disconnected(nReason);
    }
}

void MdApi::OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, 
                          CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
    if (is_error_response(pRspInfo)) {
        std::cerr << "Login failed: " << pRspInfo->ErrorMsg << std::endl;
        state_ = MdState::CONNECTED;
        
        if (callback_) {
            callback_->on_login_failed(pRspInfo->ErrorID, pRspInfo->ErrorMsg);
        }
        return;
    }
    
    std::cout << "Login successful" << std::endl;
    state_ = MdState::READY;
    
    if (callback_) {
        callback_->on_login_success();
    }
}

void MdApi::OnRspSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument,
                              CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
    if (is_error_response(pRspInfo)) {
        std::cerr << "Subscribe failed: " << pRspInfo->ErrorMsg << std::endl;
        return;
    }
    
    if (pSpecificInstrument) {
        std::cout << "Subscribe successful for: " << pSpecificInstrument->InstrumentID << std::endl;
    }
}

void MdApi::OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData) {
    if (!pDepthMarketData) {
        return;
    }
    
    // 转换为内部格式
    TickInfo tick = convert_tick_info(pDepthMarketData);
    
    // 通知回调
    if (callback_) {
        callback_->on_tick(tick);
    }
    
    // K线合成
    if (kline_enabled_ && kline_builder_) {
        kline_builder_->add_tick(tick);
        
        if (enable_kline_output_) {
            for (int period : kline_periods_) {
                auto bars = kline_builder_->get_bars(tick.instrument_id, period);
                for (const auto& bar : bars) {
                    if (callback_) {
                        callback_->on_kline(bar);
                    }
                }
            }
        }
    }
}

void MdApi::OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
    if (pRspInfo && callback_) {
        callback_->on_error(pRspInfo->ErrorID, pRspInfo->ErrorMsg);
    }
}

// 数据转换函数实现
TickInfo MdApi::convert_tick_info(const CThostFtdcDepthMarketDataField* ctp_tick) {
    TickInfo tick;
    
    if (!ctp_tick) {
        return tick;
    }
    
    tick.instrument_id = ctp_tick->InstrumentID;
    tick.trading_day = ctp_tick->TradingDay;
    tick.update_time = ctp_tick->UpdateTime;
    tick.action_day = ctp_tick->ActionDay;
    tick.last_price = ctp_tick->LastPrice;
    tick.volume = ctp_tick->Volume;
    tick.turnover = ctp_tick->Turnover;
    tick.open_interest = ctp_tick->OpenInterest;
    tick.bid_price1 = ctp_tick->BidPrice1;
    tick.bid_volume1 = ctp_tick->BidVolume1;
    tick.ask_price1 = ctp_tick->AskPrice1;
    tick.ask_volume1 = ctp_tick->AskVolume1;
    tick.open_price = ctp_tick->OpenPrice;
    tick.high_price = ctp_tick->HighestPrice;
    tick.low_price = ctp_tick->LowestPrice;
    tick.pre_close_price = ctp_tick->PreClosePrice;
    tick.upper_limit_price = ctp_tick->UpperLimitPrice;
    tick.lower_limit_price = ctp_tick->LowerLimitPrice;
    
    return tick;
}

// 工具函数实现
bool MdApi::is_error_response(CThostFtdcRspInfoField* pRspInfo) {
    return pRspInfo && pRspInfo->ErrorID != 0;
}

int MdApi::get_next_request_id() {
    return ++request_id_;
}

} // namespace ctp_api 